home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / PEAR / ErrorStack.php < prev    next >
PHP Script  |  2004-10-01  |  31KB  |  891 lines

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 5                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 3.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available through the world-wide-web at the following url:           |
  11. // | http://www.php.net/license/3_0.txt.                                  |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Gregory Beaver <cellog@php.net>                              |
  17. // |                                                                      |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: ErrorStack.php,v 1.2 2004/03/21 23:00:54 cellog Exp $
  21.  
  22. /**
  23.  * Error Stack Implementation
  24.  * 
  25.  * This is an incredibly simple implementation of a very complex error handling
  26.  * facility.  It contains the ability
  27.  * to track multiple errors from multiple packages simultaneously.  In addition,
  28.  * it can track errors of many levels, save data along with the error, context
  29.  * information such as the exact file, line number, class and function that
  30.  * generated the error, and if necessary, it can raise a traditional PEAR_Error.
  31.  * It has built-in support for PEAR::Log, to log errors as they occur
  32.  * 
  33.  * Since version 0.2alpha, it is also possible to selectively ignore errors,
  34.  * through the use of an error callback, see {@link pushCallback()}
  35.  * 
  36.  * Since version 0.3alpha, it is possible to specify the exception class
  37.  * returned from {@link push()}
  38.  * @author Greg Beaver <cellog@php.net>
  39.  * @version 0.6alpha
  40.  * @package PEAR_ErrorStack
  41.  * @category Debugging
  42.  * @license http://www.php.net/license/3_0.txt PHP License v3.0
  43.  */
  44.  
  45. /**
  46.  * Singleton storage
  47.  * 
  48.  * Format:
  49.  * <pre>
  50.  * array(
  51.  *  'package1' => PEAR_ErrorStack object,
  52.  *  'package2' => PEAR_ErrorStack object,
  53.  *  ...
  54.  * )
  55.  * </pre>
  56.  * @access private
  57.  * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON']
  58.  */
  59. $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array();
  60.  
  61. /**
  62.  * Global error callback (default)
  63.  * 
  64.  * This is only used 
  65.  * @see PEAR_ErrorStack::setDefaultCallback()
  66.  * @access private
  67.  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']
  68.  */
  69. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = false;
  70.  
  71. /**
  72.  * Global Log object (default)
  73.  * 
  74.  * This is only used 
  75.  * @see PEAR_ErrorStack::setDefaultLogger()
  76.  * @access private
  77.  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
  78.  */
  79. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false;
  80.  
  81. /**#@+
  82.  * One of four possible return values from the error Callback
  83.  * @see PEAR_ErrorStack::_errorCallback()
  84.  */
  85. /**
  86.  * If this is returned, then the error will be both pushed onto the stack
  87.  * and logged.
  88.  */
  89. define('PEAR_ERRORSTACK_PUSHANDLOG', 1);
  90. /**
  91.  * If this is returned, then the error will only be pushed onto the stack,
  92.  * and not logged.
  93.  */
  94. define('PEAR_ERRORSTACK_PUSH', 2);
  95. /**
  96.  * If this is returned, then the error will only be logged, but not pushed
  97.  * onto the error stack.
  98.  */
  99. define('PEAR_ERRORSTACK_LOG', 3);
  100. /**
  101.  * If this is returned, then the error is completely ignored.
  102.  */
  103. define('PEAR_ERRORSTACK_IGNORE', 4);
  104. /**#@-*/
  105.  
  106. /**
  107.  * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in
  108.  * the singleton method.
  109.  */
  110. define('PEAR_ERRORSTACK_ERR_NONCLASS', 1);
  111.  
  112. /**
  113.  * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()}
  114.  * that has no __toString() method
  115.  */
  116. define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2);
  117. /**
  118.  * Error Stack Implementation
  119.  *
  120.  * Usage:
  121.  * <code>
  122.  * // global error stack
  123.  * $global_stack = &PEAR_ErrorStack::singleton('MyPackage');
  124.  * // local error stack
  125.  * $local_stack = new PEAR_ErrorStack('MyPackage');
  126.  * </code>
  127.  * @copyright 2004 Gregory Beaver
  128.  * @package PEAR_ErrorStack
  129.  * @license http://www.php.net/license/3_0.txt PHP License
  130.  */
  131. class PEAR_ErrorStack {
  132.     /**
  133.      * Errors are stored in the order that they are pushed on the stack.
  134.      * @since 0.4alpha Errors are no longer organized by error level.
  135.      * This renders pop() nearly unusable, and levels could be more easily
  136.      * handled in a callback anyway
  137.      * @var array
  138.      * @access private
  139.      */
  140.     var $_errors = array();
  141.     
  142.     /**
  143.      * Package name this error stack represents
  144.      * @var string
  145.      * @access protected
  146.      */
  147.     var $_package;
  148.     
  149.     /**
  150.      * Determines whether a PEAR_Error is thrown upon every error addition
  151.      * @var boolean
  152.      * @access private
  153.      */
  154.     var $_compat = false;
  155.     
  156.     /**
  157.      * If set to a valid callback, this will be used to generate the error
  158.      * message from the error code, otherwise the message passed in will be
  159.      * used
  160.      * @var false|string|array
  161.      * @access private
  162.      */
  163.     var $_msgCallback = false;
  164.     
  165.     /**
  166.      * If set to a valid callback, this will be used to generate the error
  167.      * context for an error.  For PHP-related errors, this will be a file
  168.      * and line number as retrieved from debug_backtrace(), but can be
  169.      * customized for other purposes.  The error might actually be in a separate
  170.      * configuration file, or in a database query.
  171.      * @var false|string|array
  172.      * @access protected
  173.      */
  174.     var $_contextCallback = false;
  175.     
  176.     /**
  177.      * If set to a valid callback, this will be called every time an error
  178.      * is pushed onto the stack.  The return value will be used to determine
  179.      * whether to allow an error to be pushed or logged.
  180.      * 
  181.      * The return value must be one an PEAR_ERRORSTACK_* constant
  182.      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  183.      * @var false|string|array
  184.      * @access protected
  185.      */
  186.     var $_errorCallback = array();
  187.     
  188.     /**
  189.      * PEAR::Log object for logging errors
  190.      * @var false|Log
  191.      * @access protected
  192.      */
  193.     var $_logger = false;
  194.     
  195.     /**
  196.      * Class name to use for a PHP 5 exception that will be returned
  197.      * @var string
  198.      * @access protected
  199.      */
  200.     var $_exceptionClass = 'Exception';
  201.     
  202.     /**
  203.      * Error messages - designed to be overridden
  204.      * @var array
  205.      * @abstract
  206.      */
  207.     var $_errorMsgs = array();
  208.     
  209.     /**
  210.      * Set up a new error stack
  211.      * 
  212.      * @param string   $package name of the package this error stack represents
  213.      * @param callback $msgCallback callback used for error message generation
  214.      * @param callback $contextCallback callback used for context generation,
  215.      *                 defaults to {@link getFileLine()}
  216.      * @param boolean  $throwPEAR_Error
  217.      * @param string   $exceptionClass exception class to instantiate if
  218.      *                 in PHP 5
  219.      */
  220.     function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false,
  221.                          $throwPEAR_Error = false, $exceptionClass = null)
  222.     {
  223.         $this->_package = $package;
  224.         $this->setMessageCallback($msgCallback);
  225.         $this->setContextCallback($contextCallback);
  226.         $this->_compat = $throwPEAR_Error;
  227.         // this allows child classes to simply redefine $this->_exceptionClass
  228.         if (!is_null($exceptionClass)) {
  229.             $this->_exceptionClass = $exceptionClass;
  230.         }
  231.     }
  232.     
  233.     /**
  234.      * Return a single error stack for this package.
  235.      * 
  236.      * Note that all parameters are ignored if the stack for package $package
  237.      * has already been instantiated
  238.      * @param string   $package name of the package this error stack represents
  239.      * @param callback $msgCallback callback used for error message generation
  240.      * @param callback $contextCallback callback used for context generation,
  241.      *                 defaults to {@link getFileLine()}
  242.      * @param boolean  $throwPEAR_Error
  243.      * @param string   $exceptionClass exception class to instantiate if
  244.      *                 in PHP 5
  245.      * @param string   $stackClass class to instantiate
  246.      * @static
  247.      * @return PEAR_ErrorStack
  248.      */
  249.     function &singleton($package, $msgCallback = false, $contextCallback = false,
  250.                          $throwPEAR_Error = false, $exceptionClass = null,
  251.                          $stackClass = 'PEAR_ErrorStack')
  252.     {
  253.         if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  254.             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
  255.         }
  256.         if (!class_exists($stackClass)) {
  257.             $trace = debug_backtrace();
  258.             PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS,
  259.                 'exception', array('stackclass' => $stackClass),
  260.                 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)',
  261.                 false, $trace);
  262.         }
  263.         return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] =
  264.             &new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error,
  265.                              $exceptionClass);
  266.     }
  267.  
  268.     /**
  269.      * Internal error handler for PEAR_ErrorStack class
  270.      * 
  271.      * Dies if the error is an exception (and would have died anyway)
  272.      * @access private
  273.      */
  274.     function _handleError($err)
  275.     {
  276.         if ($err['level'] == 'exception') {
  277.             $message = $err['message'];
  278.             if (isset($_SERVER['REQUEST_URI'])) {
  279.                 echo '<br />';
  280.             } else {
  281.                 echo "\n";
  282.             }
  283.             var_dump($err['context']);
  284.             die($message);
  285.         }
  286.     }
  287.     
  288.     /**
  289.      * Set up a PEAR::Log object for all error stacks that don't have one
  290.      * @param Log $log 
  291.      * @static
  292.      */
  293.     function setDefaultLogger(&$log)
  294.     {
  295.         $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
  296.     }
  297.     
  298.     /**
  299.      * Set up a PEAR::Log object for this error stack
  300.      * @param Log $log 
  301.      */
  302.     function setLogger(&$log)
  303.     {
  304.         $this->_logger = &$log;
  305.     }
  306.     
  307.     /**
  308.      * Set an error code => error message mapping callback
  309.      * 
  310.      * This method sets the callback that can be used to generate error
  311.      * messages for any instance
  312.      * @param array|string Callback function/method
  313.      */
  314.     function setMessageCallback($msgCallback)
  315.     {
  316.         if (!$msgCallback) {
  317.             $this->_msgCallback = array(&$this, 'getErrorMessage');
  318.         } else {
  319.             if (is_callable($msgCallback)) {
  320.                 $this->_msgCallback = $msgCallback;
  321.             }
  322.         }
  323.     }
  324.     
  325.     /**
  326.      * Get an error code => error message mapping callback
  327.      * 
  328.      * This method returns the current callback that can be used to generate error
  329.      * messages
  330.      * @return array|string|false Callback function/method or false if none
  331.      */
  332.     function getMessageCallback()
  333.     {
  334.         return $this->_msgCallback;
  335.     }
  336.     
  337.     /**
  338.      * Sets a default callback to be used by all error stacks
  339.      * 
  340.      * This method sets the callback that can be used to generate error
  341.      * messages for a singleton
  342.      * @param array|string Callback function/method
  343.      * @static
  344.      */
  345.     function setDefaultCallback($callback = false)
  346.     {
  347.         if (!is_callable($callback)) {
  348.             $callback = false;
  349.         }
  350.         $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = $callback;
  351.     }
  352.     
  353.     /**
  354.      * Set an error code => error message mapping callback
  355.      * 
  356.      * This method sets the callback that can be used to generate error
  357.      * messages for any PEAR_ErrorStack instance
  358.      * @param array|string Callback function/method
  359.      */
  360.     function setContextCallback($contextCallback)
  361.     {
  362.         if (!$contextCallback) {
  363.             $this->_contextCallback = array(&$this, 'getFileLine');
  364.         } else {
  365.             if (is_callable($contextCallback)) {
  366.                 $this->_contextCallback = $contextCallback;
  367.             }
  368.         }
  369.     }
  370.     
  371.     /**
  372.      * Set an error Callback
  373.      * If set to a valid callback, this will be called every time an error
  374.      * is pushed onto the stack.  The return value will be used to determine
  375.      * whether to allow an error to be pushed or logged.
  376.      * 
  377.      * The return value must be one of the ERRORSTACK_* constants.
  378.      * 
  379.      * This functionality can be used to emulate PEAR's pushErrorHandling, and
  380.      * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of
  381.      * the error stack or logging
  382.      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  383.      * @see popCallback()
  384.      * @param string|array $cb
  385.      */
  386.     function pushCallback($cb)
  387.     {
  388.         array_push($this->_errorCallback, $cb);
  389.     }
  390.     
  391.     /**
  392.      * Remove a callback from the error callback stack
  393.      * @see pushCallback()
  394.      * @return array|string|false
  395.      */
  396.     function popCallback()
  397.     {
  398.         if (!count($this->_errorCallback)) {
  399.             return false;
  400.         }
  401.         return array_pop($this->_errorCallback);
  402.     }
  403.     
  404.     /**
  405.      * Set an error Callback for every package error stack
  406.      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  407.      * @see staticPopCallback(), pushCallback()
  408.      * @param string|array $cb
  409.      * @static
  410.      */
  411.     function staticPushCallback($cb)
  412.     {
  413.         foreach($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $unused) {
  414.             $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pushCallback($cb);
  415.         }
  416.     }
  417.     
  418.     /**
  419.      * Remove a callback from every error callback stack
  420.      * @see staticPushCallback()
  421.      * @return array|string|false
  422.      * @static
  423.      */
  424.     function staticPopCallback()
  425.     {
  426.         foreach($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $unused) {
  427.             $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->popCallback();
  428.         }
  429.     }
  430.     
  431.     /**
  432.      * Add an error to the stack
  433.      * 
  434.      * If the message generator exists, it is called with 2 parameters.
  435.      *  - the current Error Stack object
  436.      *  - an array that is in the same format as an error.  Available indices
  437.      *    are 'code', 'package', 'time', 'params', 'level', and 'context'
  438.      * 
  439.      * Next, if the error should contain context information, this is
  440.      * handled by the context grabbing method.
  441.      * Finally, the error is pushed onto the proper error stack
  442.      * @param int    $code      Package-specific error code
  443.      * @param string $level     Error level.  This is NOT spell-checked
  444.      * @param array  $params    associative array of error parameters
  445.      * @param string $msg       Error message, or a portion of it if the message
  446.      *                          is to be generated
  447.      * @param array  $repackage If this error re-packages an error pushed by
  448.      *                          another package, place the array returned from
  449.      *                          {@link pop()} in this parameter
  450.      * @param array  $backtrace Protected parameter: use this to pass in the
  451.      *                          {@link debug_backtrace()} that should be used
  452.      *                          to find error context
  453.      * @return PEAR_Error|array|Exception
  454.      *                          if compatibility mode is on, a PEAR_Error is also
  455.      *                          thrown.  If the class Exception exists, then one
  456.      *                          is returned to allow code like:
  457.      * <code>
  458.      * throw ($stack->push(MY_ERROR_CODE, 'error', array('username' => 'grob')));
  459.      * </code>
  460.      * 
  461.      * The errorData property of the exception class will be set to the array
  462.      * that would normally be returned.  If a PEAR_Error is returned, the userinfo
  463.      * property is set to the array
  464.      * 
  465.      * Otherwise, an array is returned in this format:
  466.      * <code>
  467.      * array(
  468.      *    'code' => $code,
  469.      *    'params' => $params,
  470.      *    'package' => $this->_package,
  471.      *    'level' => $level,
  472.      *    'time' => time(),
  473.      *    'context' => $context,
  474.      *    'message' => $msg,
  475.      * //['repackage' => $err] repackaged error array
  476.      * );
  477.      * </code>
  478.      */
  479.     function push($code, $level = 'error', $params = array(), $msg = false,
  480.                   $repackage = false, $backtrace = false)
  481.     {
  482.         $context = false;
  483.         // grab error context
  484.         if ($this->_contextCallback) {
  485.             if (!$backtrace) {
  486.                 $backtrace = debug_backtrace();
  487.             }
  488.             $context = call_user_func($this->_contextCallback, $code, $params, $backtrace);
  489.         }
  490.         
  491.         // save error
  492.         $time = explode(' ', microtime());
  493.         $time = $time[1] + $time[0];
  494.         $err = array(
  495.                 'code' => $code,
  496.                 'params' => $params,
  497.                 'package' => $this->_package,
  498.                 'level' => $level,
  499.                 'time' => $time,
  500.                 'context' => $context,
  501.                 'message' => $msg,
  502.                );
  503.  
  504.         // set up the error message, if necessary
  505.         if ($this->_msgCallback) {
  506.             $msg = call_user_func_array($this->_msgCallback,
  507.                                         array(&$this, $err));
  508.             $err['message'] = $msg;
  509.         }
  510.         
  511.         
  512.         if ($repackage) {
  513.             $err['repackage'] = $repackage;
  514.         }
  515.         $push = $log = true;
  516.         $callback = $this->popCallback();
  517.         if (is_callable($callback)) {
  518.             $this->pushCallback($callback);
  519.             switch(call_user_func($callback, $err)){
  520.                 case PEAR_ERRORSTACK_IGNORE: 
  521.                     return $err;
  522.                 break;
  523.                 case PEAR_ERRORSTACK_PUSH: 
  524.                     $log = false;
  525.                 break;
  526.                 case PEAR_ERRORSTACK_LOG: 
  527.                     $push = false;
  528.                 break;
  529.                 // anything else returned has the same effect as pushandlog
  530.             }
  531.         } elseif (is_callable($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'])) {
  532.             switch(call_user_func($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'], $err)){
  533.                 case PEAR_ERRORSTACK_IGNORE: 
  534.                     return $err;
  535.                 break;
  536.                 case PEAR_ERRORSTACK_PUSH: 
  537.                     $log = false;
  538.                 break;
  539.                 case PEAR_ERRORSTACK_LOG: 
  540.                     $push = false;
  541.                 break;
  542.                 // anything else returned has the same effect as pushandlog
  543.             }
  544.         }
  545.         if ($push) {
  546.             array_unshift($this->_errors, $err);
  547.         }
  548.         if ($log) {
  549.             if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) {
  550.                 $this->_log($err);
  551.             }
  552.         }
  553.         if ($this->_compat && $push) {
  554.             return $this->raiseError($msg, $code, null, null, $err);
  555.         }
  556.         if (class_exists($this->_exceptionClass)) {
  557.             $exception = $this->_exceptionClass;
  558.             $ret = new $exception($msg, $code);
  559.             $ret->errorData = $err;
  560.         }
  561.         return $err;
  562.     }
  563.     
  564.     /**
  565.      * Static version of {@link push()}
  566.      * 
  567.      * @param string $package   Package name this error belongs to
  568.      * @param int    $code      Package-specific error code
  569.      * @param string $level     Error level.  This is NOT spell-checked
  570.      * @param array  $params    associative array of error parameters
  571.      * @param string $msg       Error message, or a portion of it if the message
  572.      *                          is to be generated
  573.      * @param array  $repackage If this error re-packages an error pushed by
  574.      *                          another package, place the array returned from
  575.      *                          {@link pop()} in this parameter
  576.      * @param array  $backtrace Protected parameter: use this to pass in the
  577.      *                          {@link debug_backtrace()} that should be used
  578.      *                          to find error context
  579.      * @return PEAR_Error|null|Exception
  580.      *                          if compatibility mode is on, a PEAR_Error is also
  581.      *                          thrown.  If the class Exception exists, then one
  582.      *                          is returned to allow code like:
  583.      * <code>
  584.      * throw ($stack->push(MY_ERROR_CODE, 'error', array('username' => 'grob')));
  585.      * </code>
  586.      * @static
  587.      */
  588.     function staticPush($package, $code, $level = 'error', $params = array(),
  589.                         $msg = false, $repackage = false, $backtrace = false)
  590.     {
  591.         $s = &PEAR_ErrorStack::singleton($package);
  592.         if ($s->_contextCallback) {
  593.             if (!$backtrace) {
  594.                 $backtrace = debug_backtrace();
  595.             }
  596.         }
  597.         return $s->push($code, $level, $params, $msg, $repackage, $backtrace);
  598.     }
  599.     
  600.     /**
  601.      * Log an error using PEAR::Log
  602.      * @param array $err Error array
  603.      * @param array $levels Error level => Log constant map
  604.      * @access protected
  605.      */
  606.     function _log($err, $levels = array(
  607.                 'exception' => PEAR_LOG_CRIT,
  608.                 'alert' => PEAR_LOG_ALERT,
  609.                 'critical' => PEAR_LOG_CRIT,
  610.                 'error' => PEAR_LOG_ERR,
  611.                 'warning' => PEAR_LOG_WARNING,
  612.                 'notice' => PEAR_LOG_NOTICE,
  613.                 'info' => PEAR_LOG_INFO,
  614.                 'debug' => PEAR_LOG_DEBUG))
  615.     {
  616.         if (isset($levels[$err['level']])) {
  617.             $level = $levels[$err['level']];
  618.         } else {
  619.             $level = PEAR_LOG_INFO;
  620.         }
  621.         if ($this->_logger) {
  622.             $this->_logger->log($err['message'], $level, $err);
  623.         } else {
  624.             $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']->log($err['message'], $level, $err);
  625.         }
  626.     }
  627.  
  628.     
  629.     /**
  630.      * Pop an error off of the error stack
  631.      * 
  632.      * @return false|array
  633.      * @since 0.4alpha it is no longer possible to specify a specific error
  634.      * level to return - the last error pushed will be returned, instead
  635.      */
  636.     function pop()
  637.     {
  638.         return @array_shift($this->_errors);
  639.     }
  640.     
  641.     /**
  642.      * Determine whether there are any errors on the stack
  643.      * @return boolean
  644.      */
  645.     function hasErrors()
  646.     {
  647.         return count($this->_errors);
  648.     }
  649.     
  650.     /**
  651.      * Retrieve all errors since last purge
  652.      * 
  653.      * @param boolean $purge set in order to empty the error stack
  654.      * @return array
  655.      */
  656.     function getErrors($purge = false)
  657.     {
  658.         if (!$purge) {
  659.             return $this->_errors;
  660.         }
  661.         $ret = $this->_errors;
  662.         $this->_errors = array();
  663.         return $ret;
  664.     }
  665.     
  666.     /**
  667.      * Determine whether there are any errors on any error stack
  668.      * @return boolean
  669.      * @static
  670.      */
  671.     function staticHasErrors()
  672.     {
  673.         foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
  674.             if ($obj->hasErrors()) {
  675.                 return true;
  676.             }
  677.         }
  678.         return false;
  679.     }
  680.     
  681.     /**
  682.      * Get a list of all errors since last purge, organized by package
  683.      * @param boolean $clearStack Set to purge the error stack of existing errors
  684.      * @param boolean $merge Set to return a flat array, not organized by package
  685.      * @param array   $sortfunc Function used to sort a merged array - default
  686.      *        sorts by time, and should be good for most cases
  687.      * @static
  688.      * @return array 
  689.      */
  690.     function staticGetErrors($purge = false, $merge = false, $sortfunc = array('PEAR_ErrorStack', '_sortErrors'))
  691.     {
  692.         $ret = array();
  693.         if (!is_callable($sortfunc)) {
  694.             $sortfunc = array('PEAR_ErrorStack', '_sortErrors');
  695.         }
  696.         foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
  697.             $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge);
  698.             if ($test) {
  699.                 if ($merge) {
  700.                     $ret = array_merge($ret, $test);
  701.                 } else {
  702.                     $ret[$package] = $test;
  703.                 }
  704.             }
  705.         }
  706.         if ($merge) {
  707.             usort($ret, $sortfunc);
  708.         }
  709.         return $ret;
  710.     }
  711.     
  712.     /**
  713.      * Error sorting function, sorts by time
  714.      * @access private
  715.      */
  716.     function _sortErrors($a, $b)
  717.     {
  718.         if ($a['time'] == $b['time']) {
  719.             return 0;
  720.         }
  721.         if ($a['time'] < $b['time']) {
  722.             return 1;
  723.         }
  724.         return -1;
  725.     }
  726.  
  727.     /**
  728.      * Standard file/line number/function/class context callback
  729.      *
  730.      * This function uses a backtrace generated from {@link debug_backtrace()}
  731.      * and so will not work at all in PHP < 4.3.0.  The frame should
  732.      * reference the frame that contains the source of the error.
  733.      * @return array|false either array('file' => file, 'line' => line,
  734.      *         'function' => function name, 'class' => class name) or
  735.      *         if this doesn't work, then false
  736.      * @param array Results of debug_backtrace()
  737.      * @param unused
  738.      * @param integer backtrace frame.
  739.      * @static
  740.      */
  741.     function getFileLine($code, $params, $backtrace = null)
  742.     {
  743.         if ($backtrace === null) {
  744.             return false;
  745.         }
  746.         $frame = 0;
  747.         $functionframe = 1;
  748.         if (!isset($backtrace[1])) {
  749.             $functionframe = 0;
  750.         } else {
  751.             while (isset($backtrace[$functionframe]['function']) &&
  752.                   $backtrace[$functionframe]['function'] == 'eval' &&
  753.                   isset($backtrace[$functionframe + 1])) {
  754.                 $functionframe++;
  755.             }
  756.         }
  757.         if (isset($backtrace[$frame])) {
  758.             if (!isset($backtrace[$frame]['file'])) {
  759.                 $frame++;
  760.             }
  761.             $funcbacktrace = $backtrace[$functionframe];
  762.             $filebacktrace = $backtrace[$frame];
  763.             $ret = array('file' => $filebacktrace['file'],
  764.                          'line' => $filebacktrace['line']);
  765.             // rearrange for eval'd code or create function errors
  766.             if (strpos($filebacktrace['file'], '(') && 
  767.                   preg_match(';^(.*?)\((\d+)\) : (.*?)$;', $filebacktrace['file'],
  768.                   $matches)) {
  769.                 $ret['file'] = $matches[1];
  770.                 $ret['line'] = $matches[2] + 0;
  771.             }
  772.             if (isset($funcbacktrace['function']) && isset($backtrace[1])) {
  773.                 if ($funcbacktrace['function'] != 'eval') {
  774.                     if ($funcbacktrace['function'] == '__lambda_func') {
  775.                         $ret['function'] = 'create_function() code';
  776.                     } else {
  777.                         $ret['function'] = $funcbacktrace['function'];
  778.                     }
  779.                 }
  780.             }
  781.             if (isset($funcbacktrace['class']) && isset($backtrace[1])) {
  782.                 $ret['class'] = $funcbacktrace['class'];
  783.             }
  784.             return $ret;
  785.         }
  786.         return false;
  787.     }
  788.     
  789.     /**
  790.      * Standard error message generation callback
  791.      * 
  792.      * This method may also be called by a custom error message generator
  793.      * to fill in template values from the params array, simply
  794.      * set the third parameter to the error message template string to use
  795.      * 
  796.      * The special variable %__msg% is reserved: use it only to specify
  797.      * where a message passed in by the user should be placed in the template,
  798.      * like so:
  799.      * 
  800.      * Error message: %msg% - internal error
  801.      * 
  802.      * If the message passed like so:
  803.      * 
  804.      * <code>
  805.      * $stack->push(ERROR_CODE, 'error', array(), 'server error 500');
  806.      * </code>
  807.      * 
  808.      * The returned error message will be "Error message: server error 500 -
  809.      * internal error"
  810.      * @param PEAR_ErrorStack
  811.      * @param array
  812.      * @param string|false Pre-generated error message template
  813.      * @static
  814.      * @return string
  815.      */
  816.     function getErrorMessage(&$stack, $err, $template = false)
  817.     {
  818.         if ($template) {
  819.             $mainmsg = $template;
  820.         } else {
  821.             $mainmsg = $stack->getErrorMessageTemplate($err['code']);
  822.         }
  823.         $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg);
  824.         if (count($err['params'])) {
  825.             foreach ($err['params'] as $name => $val) {
  826.                 if (is_array($val)) {
  827.                     $val = implode(', ', $val);
  828.                 }
  829.                 if (is_object($val)) {
  830.                     if (method_exists($val, '__toString')) {
  831.                         $val = $val->__toString();
  832.                     } else {
  833.                         PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING,
  834.                             'warning', array('obj' => get_class($val)),
  835.                             'object %obj% passed into getErrorMessage, but has no __toString() method');
  836.                         $val = 'Object';
  837.                     }
  838.                 }
  839.                 $mainmsg = str_replace('%' . $name . '%', $val,  $mainmsg);
  840.             }
  841.         }
  842.         return $mainmsg;
  843.     }
  844.     
  845.     /**
  846.      * Standard Error Message Template generator from code
  847.      * @return string
  848.      */
  849.     function getErrorMessageTemplate($code)
  850.     {
  851.         if (!isset($this->_errorMsgs[$code])) {
  852.             return '%__msg%';
  853.         }
  854.         return $this->_errorMsgs[$code];
  855.     }
  856.     
  857.     /**
  858.      * Set the Error Message Template array
  859.      * 
  860.      * The array format must be:
  861.      * <pre>
  862.      * array(error code => 'message template',...)
  863.      * </pre>
  864.      * 
  865.      * Error message parameters passed into {@link push()} will be used as input
  866.      * for the error message.  If the template is 'message %foo% was %bar%', and the
  867.      * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will
  868.      * be 'message one was six'
  869.      * @return string
  870.      */
  871.     function setErrorMessageTemplate($template)
  872.     {
  873.         $this->_errorMsgs = $template;
  874.     }
  875.     
  876.     
  877.     /**
  878.      * emulate PEAR::raiseError()
  879.      * 
  880.      * @return PEAR_Error
  881.      */
  882.     function raiseError()
  883.     {
  884.         require_once 'PEAR.php';
  885.         $args = func_get_args();
  886.         return call_user_func_array(array('PEAR', 'raiseError'), $args);
  887.     }
  888. }
  889. $stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
  890. $stack->pushCallback(array('PEAR_ErrorStack', '_handleError'));
  891. ?>